﻿using IOP.SgrA;
using IOP.SgrA.SilkNet.Vulkan;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Silk.NET.Vulkan;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;

namespace VkSample91
{
    public class OITGroupRenderingMiddleware : IProductionLineMiddleware<PrimaryVulkanRenderGroup>
    {
        private readonly WindowOption Options;

        public OITGroupRenderingMiddleware(IOptions<WindowOption> options)
        {
            Options = options.Value;
        }

        public void Invoke(PrimaryVulkanRenderGroup group, RenderingProductionLineDelegate<PrimaryVulkanRenderGroup> next)
        {
            try
            {
                var camera = group.Camera;
                var view = camera.ViewMatrix;
                var project = camera.ProjectionMatrix;
                var queue = group.WorkQueues[0].Queue;
                var semaphores = group.Semaphores;
                var cmdBuffer = group.PrimaryCommandBuffer;
                var pass = group.RenderPass;
                var lDevice = group.LogicDevice;

                var ssbo = group.Pipeline.GetPipelineTexture(0, 0);
                Span<byte> local = stackalloc byte[8];
                float a = 0.9f;
                uint b = 0;
                MemoryMarshal.Write(local.Slice(0, 4), ref a);
                MemoryMarshal.Write(local.Slice(4, 4), ref b);
                ssbo.UpdateTextureMemoryData(local);

                int index = 0;
                Span<IOP.SgrA.SilkNet.Vulkan.WriteDescriptorSet> writes = new IOP.SgrA.SilkNet.Vulkan.WriteDescriptorSet[3];
                foreach (var item in group.Pipeline.PipelineTextures) writes[index++] = item.Value.WriteDescriptorSet;
                lDevice.UpdateDescriptorSets(writes.Slice(1, 2), null);

                VulkanFrameBuffer framebuffer = group.RenderPass.GetFramebuffer(0);
                cmdBuffer.Reset();
                cmdBuffer.Begin();
                cmdBuffer.BeginRenderPass(pass, framebuffer, pass.BeginOption, SubpassContents.Inline);
                cmdBuffer.BindPipeline(PipelineBindPoint.Graphics, group.Pipeline);
                var viewPort = group.Camera.Viewport;
                cmdBuffer.SetViewport(new Viewport(viewPort.X, viewPort.Y, viewPort.Width, viewPort.Height, viewPort.MinDepth, viewPort.MaxDepth));
                cmdBuffer.SetScissor(new Rect2D(null, new Extent2D((uint)viewPort.Width, (uint)viewPort.Height)));
                foreach (var item in group.GetContexts())
                {
                    item.SetViewMatrix(in view);
                    item.SetProjectionMatrix(in project);
                    group.ItemProductionLine(item);
                }
                cmdBuffer.EndRenderPass();
                cmdBuffer.End();
                var submitInfo = new SubmitOption
                {
                    WaitDstStageMask = new PipelineStageFlags[] { PipelineStageFlags.PipelineStageColorAttachmentOutputBit },
                    Buffers = new CommandBuffer[] { cmdBuffer.RawHandle },
                    SignalSemaphores = new Semaphore[] { semaphores[0] }
                };
                lDevice.Submit(queue, new Fence(null), submitInfo);
                foreach (var item in group.GetChildrens())
                {
                    item.GroupRendering(group.CurrentFrame);
                }
            }
            catch (Exception e)
            {
                group.Logger.LogError(e.Message + "\r\n" + e.StackTrace);
                group.Disable();
            }
        }
    }
}
